#include "lisoundlisten.h"


LiSoundListen::LiSoundListen(QAudioFormat::Endian byteOrder, int channels, QString codec, int samplerate, int sampleSize, QAudioFormat::SampleType sampleType, QString savePath,QObject *parent):QObject(parent)
{
    //设置音频格式

    setByteOrder (byteOrder);
    setChannelCount (channels);
    setCodec (codec);
    setSampleRate (samplerate);
    setSampleSize (sampleSize);
    setSampleType (sampleType);
    //判断硬件是否支持所设格式
    bool is1=(QAudioDeviceInfo::defaultInputDevice().isFormatSupported (m_audioFormat));
    if(!is1)
    {
        //获取与所设格式最接近的格式
        m_audioFormat=QAudioDeviceInfo::defaultInputDevice().nearestFormat (m_audioFormat);
    }
    //实例化音频输入
    m_audioInputListen=new QAudioInput(QAudioDeviceInfo::defaultInputDevice (),m_audioFormat,this);
    m_audioInputListenIO=m_audioInputListen->start ();//获取IO指针

    //同上,但为同步音频输出
    //}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
    is1=QAudioDeviceInfo::defaultOutputDevice().isFormatSupported (m_audioFormat);
    if(!is1)
    {
        m_audioFormat=QAudioDeviceInfo::defaultOutputDevice().nearestFormat (m_audioFormat);
    }
    m_audioOutput=new QAudioOutput(QAudioDeviceInfo::defaultInputDevice (),m_audioFormat,this);
    m_audioOutputListenIO=m_audioOutput->start ();
    //}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}



    //    this->savePath=savePath;
    this->savePath=QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation).first();//获取系统对应的路径防止自设路径不可用,可对自设路径进行判断,不可用后再执行此函数
    //    foreach (QString path, QStandardPaths::standardLocations(QStandardPaths::DataLocation)) {
    //        qDebug()<<path;
    //    }
    qDebug()<<this->savePath;

    sampleMaxSoundeSize=0;//初始化采样最大值
    saveFile=new QFile(this->savePath+"/source.pcm");//实例化保存对象
    controlALL=false;//一开始设为不可用
    doubleTimerSet ();//计时器配置
    controlEmitAppearSound=true;//允许发射有音信号
    isWrangle=false;//
    controlsaveFile=false;//不允许数据写入保存文件
    standardMaxSoundSize=90000;//初始化阈值为不可为之值
    m_Buffer=NULL;

    isAppear=false;
    soundHead=NULL;
    soundHeadLen=0;
    repaidHeadSave=new LimitQueue(5);


    connect (this,SIGNAL(appearSound()),this,SLOT(onAppearSound()));//对应连接
    connect (this,SIGNAL(stopSound()),this,SLOT(onStopSound()));//对应连接
    connect (m_audioInputListenIO,SIGNAL(readyRead()),this,SLOT(handleInputData()));//但收到音频流就处理
}

LiSoundListen::~LiSoundListen()
{
    delete m_audioInputListen;
    delete m_audioOutputListenIO;
}

void LiSoundListen::handleInputData ()
{
    if(!controlALL)//总控
    {
        return;
    }
    //Check the number of samples in input buffer
    qint64 len = m_audioInputListen->bytesReady();//返回可读数据长度


    //Read sound samples from input device to buffer

//    if(m_Buffer!=NULL)
//    {
//        delete[] m_Buffer;
//    }
    m_Buffer=new char[len];//创建临时存储音频数据的位置
    qint64 l = m_audioInputListenIO->read(m_Buffer,len);//读取数据到缓存区
    //    char* shishi=mBuffer.data();

    if(l > 0) {
        //Assign sound samples to short array
        short* resultingData = (short*)m_Buffer;//强制转换
        short *outdata=resultingData;//其实似乎不用如此繁杂,暂时懒得改(就是怂,怕出问题)

        int iIndex=0;
        //低通道滤噪,用了就崩看起来很正常,也不会认为有越界的问题,但是事实是用了就崩
        //有兴趣的可以改成true试一试,和机器也有一定关系
        if(false) {
            //Remove noise using Low Pass filter algortm[Simple algorithm used to remove noise]
            for ( iIndex=1; iIndex < l; iIndex++ ) {
                outdata[ iIndex ] =0.333 * resultingData[iIndex] + (1.0-0.333) * outdata[iIndex-1];
            }
        }

        int MaxSoundeSize = 0;//配合最大算法(名字乱说的)
        double averageSoundSize=0;//配合平均算法(名字乱说的)
        //遍历音频数据
        for ( iIndex=0; iIndex < l; iIndex++ )
        {
            //取所有绝对值之和求平均做当前采样最大值
            if(outdata[iIndex]>=0)
            {
                averageSoundSize+=outdata[iIndex];
            }
            else
            {
                averageSoundSize-=outdata[iIndex];
            }

            //取最大值做当前采样最大值
            //qDebug()<<outdata[iIndex];//调试信息,开了提高崩溃概率
            //MaxSoundeSize = MaxSoundeSize>=outdata[ iIndex ] ? MaxSoundeSize : outdata[ iIndex ];
            //}
        }

        currentMaxSoundeSize=(int)(averageSoundSize/l);//求平均
        //        currentMaxSoundeSize=MaxSoundeSize;//最大赋值
        //        qDebug()<<currentMaxSoundeSize;//调试信息

        //采样控制(采样时不执行其他操作)
        if(controlSampleMaxSoundeSize)
        {
            //取最大值(感觉用最大值好些)
            sampleMaxSoundeSize=sampleMaxSoundeSize>=currentMaxSoundeSize?sampleMaxSoundeSize:currentMaxSoundeSize;

            //取平均值
            //            if(sampleMaxSoundeSize==0)
            //            {
            //                sampleMaxSoundeSize=currentMaxSoundeSize;
            //            }
            //            else
            //            {
            //                sampleMaxSoundeSize=(sampleMaxSoundeSize+currentMaxSoundeSize)/2;
            //            }

        }
        else
        {
            //            qDebug()<<"进入了吗?"+QString::number (currentMaxSoundeSize)+"   "+QString::number(standardMaxSoundSize);
            //出现高于标准音峰的值发射信号
            if(currentMaxSoundeSize>standardMaxSoundSize)
            {//有人说话
                if(controlEmitAppearSound)
                {
                    qDebug()<<"敢问汝在乎";
                    emit appearSound ();
                    controlEmitAppearSound=false;
                }
                isWrangle=true;
            }
            //保存文件
            if(controlsaveFile)
            {
                saveFile->write ((char*)outdata,l);
            }

        }
        m_audioOutputListenIO->write ((char*)outdata,l);
    }
//    if(soundHead!=NULL)
//    {
//        soundHeadLen=0;
//        delete[] soundHead;
//    }
//    soundHeadLen=l;
//    soundHead=m_Buffer;
    if(!isAppear)
    {
        repaidHeadSave->addElement (m_Buffer,l);
    }
    else
    {
        delete[] m_Buffer;
    }
    m_Buffer=NULL;
}

//采样控制
void LiSoundListen::setControlSampleMaxSoundeSize (bool value)
{
    qDebug()<<"我就想知道我的多线程进来没";
    if(value)//采样时停止其他一切活动
    {
        qDebug()<<"进来了";
        smallTimer.stop ();
        bigTimer.stop ();
        controlEmitAppearSound=false;
        if(controlsaveFile)
        {
            setControlsaveFile (false);
        }
        sampleMaxSoundeSize=0;
    }
    else
    {
        qDebug()<<"出去了:"<<QString::number (sampleMaxSoundeSize);
        controlEmitAppearSound=true;
        sampleMaxSoundeSize=sampleMaxSoundeSize*1.1;//阈值修正
        setStandardMaxSoundSize (sampleMaxSoundeSize);
        emit sampleSoundSize(sampleMaxSoundeSize);
    }
    controlSampleMaxSoundeSize=value;
}

//是否允许写入文件
void LiSoundListen::setControlsaveFile (bool isSave)
{

    if(isSave)
    {

        if(saveFile->open (QIODevice::WriteOnly | QIODevice::Truncate))
        {
            qDebug()<<"FileOpen";
        }

//        if(soundHead!=NULL&&soundHeadLen!=0)
//        {
//            saveFile->write (soundHead,soundHeadLen);
//        }
        int waitWriteCurrentSize=repaidHeadSave->getCurrentSize ();
        if(waitWriteCurrentSize>0)
        {
            LimitElement *tail=repaidHeadSave->getTail ();
            while(tail->last!=0)
            {
                saveFile->write (tail->data,tail->len);
                tail=tail->last;
            }
            saveFile->flush ();
        }
    }
    else
    {
        qDebug()<<"FileClose";
        saveFile->flush ();
        saveFile->close ();
    }
    controlsaveFile=isSave;
}


//计时器处理
/*
 * 设小计时器为A结束为AO,大计时器为B结束为BO
 * 每次判断有人讲话时isWrangle都被刷成true
 * AO有人讲话则自启,没人讲话启动B
 * BO有人讲话在启动A,没人讲话就发射stopSound ()
 * 同时设置对应标志位,允许appearSound()发射
*/
void LiSoundListen::smallTimeOver ()
{
    if(isWrangle)
    {
        qDebug()<<"smallOver";
        isWrangle=false;
        smallTimer.start ();
    }
    else
    {
        qDebug()<<"BigStart";
        bigTimer.start ();
    }
}

void LiSoundListen::bigTimeOver ()
{
    if(isWrangle)
    {qDebug()<<"smallStart";
        isWrangle=false;
        smallTimer.start ();
    }
    else
    {qDebug()<<"bigOver";
        controlEmitAppearSound=true;
        emit stopSound ();
    }
}

//出现声音,设置文件允许读取
//开启计时器
void LiSoundListen::onAppearSound ()
{
    if(!controlsaveFile)
        setControlsaveFile (true);
    smallTimer.start ();
    isAppear=true;
    qDebug()<<"有人冒泡";
}

//声音停止,关闭文件输入
void LiSoundListen::onStopSound ()
{
    if(controlsaveFile)
        setControlsaveFile (false);
    isAppear=false;
    qDebug()<<"有人潜水";
}








//计时器配置
void LiSoundListen::doubleTimerSet ()
{
    smallTimer.setInterval (500);
    smallTimer.setSingleShot (true);
    connect (&smallTimer,SIGNAL(timeout()),this,SLOT(smallTimeOver()));
    bigTimer.setInterval (1000);
    bigTimer.setSingleShot (true);
    connect (&bigTimer,SIGNAL(timeout()),this,SLOT(bigTimeOver()));
}
